import axios from 'axios'

import Crypto from '@/utils/crypto-js'
import Base64 from '@/utils/crypto-js/base64'
import { randomString } from '@/utils/stringUtil'

import config from './config'

const {
  EXCEL_DOWNLOAD,
  EXCEL_UPLOAD,
  IMG_ORIGINAL,
  UPLOAD_BUCKET,
  UPLOAD_BUCKET_EXCEL,
  UPLOAD_BUCKET_ZIP,
  UPLOAD_KEY,
  UPLOAD_KEY_EXCEL,
  UPLOAD_KEY_ZIP,
  UPLOAD_SAVE_KEY,
  UPLOAD_SAVE_KEY_ERRORLOG,
  UPLOAD_SAVE_KEY_EXCEL,
  UPLOAD_SAVE_KEY_ZIP,
  ZIP_DOWNLOAD,
  IMG_UPLOAD,
} = config
const CONFIG_ENV = import.meta.env.MODE
const DEP_ENV = import.meta.env.VITE_DEP_ENV

export const uploadKeysConfig = {
  key: '',
  sec: '',
}
export const resetUploadKeys = ({ randomSetting1: key, randomSetting2: sec, env, enableEbIcon } = {}) => {
  Object.assign(uploadKeysConfig, { key, sec })
  const needEbeiFlag = enableEbIcon === true
  const zheYi = env === 'uat'
  if (!zheYi && !needEbeiFlag) return
  const head = document.getElementsByTagName('head')[0]
  const rels = ['shortcut icon', 'icon']
  rels.forEach(rel => {
    const linkTag = document.createElement('link')
    linkTag.href = zheYi ? './z1-favicon.png' : './yb-favicon.png'
    linkTag.setAttribute('rel', rel)
    linkTag.setAttribute('type', 'image/x-icon')
    head.appendChild(linkTag)
  })
}

/**
 * 上传签名
 * @param type
 * @returns {{OSSAccessKeyId: (string|string),
 * signature, success_action_status: number,
 * Filename: string, key: string,
 * policy: (*|string|Uint8Array)}|{signature, policy}}
 */
export const getUploadAuth =
  (type, saveLocalFileName = true) =>
  (file, defaultName) => {
    let saveKey = UPLOAD_SAVE_KEY
    let bucket = UPLOAD_BUCKET
    let uploadKey = UPLOAD_KEY
    let uploadedUriPrefix = IMG_ORIGINAL
    defaultName = defaultName || file.name

    if (type === 'excel') {
      saveKey = UPLOAD_SAVE_KEY_EXCEL
      bucket = UPLOAD_BUCKET_EXCEL
      uploadKey = UPLOAD_KEY_EXCEL
      uploadedUriPrefix = EXCEL_DOWNLOAD
    }
    if (type === 'zip') {
      saveKey = UPLOAD_SAVE_KEY_ZIP
      bucket = UPLOAD_BUCKET_ZIP
      uploadKey = UPLOAD_KEY_ZIP
      uploadedUriPrefix = ZIP_DOWNLOAD
    }
    if (type === 'errorLog') {
      saveKey = UPLOAD_SAVE_KEY_ERRORLOG
      bucket = UPLOAD_BUCKET_EXCEL
      uploadKey = UPLOAD_KEY_EXCEL
      uploadedUriPrefix = EXCEL_UPLOAD
    }
    // 设置上传的信息
    const nowDate = new Date()
    let localNowDate = new Date()
    const now = localNowDate.getTime() + 30 * 60
    const month = nowDate.getMonth() + 1
    const day = nowDate.getDate()
    const hour = nowDate.getHours()
    const min = nowDate.getMinutes()
    const sec = nowDate.getSeconds()
    const random32 = randomString()
    const suffix = file.name || type

    try {
      if (nowDate.getMonth() !== localNowDate.getMonth()) {
        window.uploadErrorLog &&
          window.uploadErrorLog({
            message: '本机时间与服务器时间可能不一致',
            server: nowDate.toLocaleDateString(),
            local: localNowDate.toLocaleDateString(),
          })
      }
    } catch (e) {
      console.log(e)
    }
    uploadKey = uploadKeysConfig.key
    let data
    let policyText = {
      bucket,
      'save-key': uploadKeysConfig.key,
      expiration: now,
    }

    policyText = {
      expiration: '2099-01-01T12:00:00.000Z', // 设置该Policy的失效时间，超过这个失效时间之后，就没有办法通过这个policy上传文件了
      conditions: [
        ['content-length-range', 0, 1048576000], // 设置上传文件的大小限制
      ],
    }
    let policyBase64 = Base64.encode(JSON.stringify(policyText))
    let bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, uploadKeysConfig.sec, { asBytes: true })
    const signature = Crypto.util.bytesToBase64(bytes)
    let fileName = `${CONFIG_ENV}/${saveKey}`

    fileName = fileName.replace(/[/]{2,}/g, '/')
    if (type === 'errorLog') {
      fileName = saveKey.replace('/errorLog/', `errorLog/${CONFIG_ENV}/`)
    }
    const [name] = (defaultName || '').split('.')
    fileName = fileName.replace(/[{][\w]+[}]/gim, str => {
      switch (str) {
        case '{year}':
          return nowDate.getFullYear()
        case '{mon}':
          return month >= 10 ? month : `0${month}`
        case '{day}':
          return day >= 10 ? day : `0${day}`
        case '{hour}':
          return hour >= 10 ? hour : `0${hour}`
        case '{min}':
          return min >= 10 ? min : `0${min}`
        case '{sec}':
          return sec >= 10 ? sec : `0${sec}`
        case '{random32}':
          str = random32
          if (saveLocalFileName) {
            const encodeName = name.replace(
              /[`@#$%^&*()\+=<>?:"{}|,.\/;'\\[\]·~！@#￥%……&*（）——\-+={}|《》？：“”【】、；‘'，。、]|\s+/g,
              '_',
            )
            // 特殊字符转成_
            str = `${random32}${(encodeName && '/') || ''}${encodeName}`
          }
          return str
        case '{suffix}':
          return (/[.](\w+)$/i.test(suffix) && RegExp.$1) || (suffix === 'errorLog' ? '.log' : suffix)
        default:
          return ''
      }
    })
    data = {
      // Filename: fileName,
      key: fileName,
      policy: policyBase64,
      OSSAccessKeyId: uploadKey,
      // eslint-disable-next-line camelcase
      success_action_status: 200, // 让服务端返回200，不设置则默认返回204
      signature,
    }
    file.serverFileUri = `${uploadedUriPrefix}/${fileName.replace(/[/]{2,}/g, '/')}`
    if (CONFIG_ENV === 'production') {
      if (DEP_ENV === 'seb') {
        file.serverFileUri = `/${fileName.replace(/[/]{2,}/g, '/')}`
      }
    }
    file.requestType = 'oss_aliyun'
    file.serverRelativeFileUri = fileName
    file.thumbUrl = file.serverFileUri
    file.url = file.serverFileUri
    file.originUrl = file.serverFileUri
    file.requestCheckDone = false

    return data
  }

export const dataURLtoFile = (dataURL, fileName) => {
  const arr = dataURL.split(',')
  const mime = arr[0].match(/:(.*?);/)[1] // 切出文件类型
  const suffix = mime.split('/')[1] // 切出文件后缀
  const bstr = atob(arr[1]) // 返回ASCII编码
  let n = bstr.length // 获取编码长度
  const u8arr = new Uint8Array(n) // 创建一个无符号8位视图对象
  while (n--) {
    // 还原unicode
    u8arr[n] = bstr.charCodeAt(n)
  }
  return new File([u8arr], `${fileName}.${suffix}`, {
    type: mime,
  })
}

export const uploadFileToOss = async file => {
  const params = { ...getUploadAuth()(file), file }
  const formData = new FormData()
  Object.keys(params).forEach(key => {
    formData.set(key, params[key])
  })
  await axios.post(IMG_UPLOAD, formData)
}
